<!--
// 
// GFileListUpload.vue
// rzhwweb
// 
// Created by 区区电脑 on 2024/03/14.
// 
-->
<template>
    <div class="GFileListUpload">
        <div class="uploaded-list">
            <template v-for="path in state.uploadedPathList" :key="path">
                <div class="uploaded-file">
                    <div class="file">{{ getFileName(path) }}</div>
                    <div class="show" @click="preview(path)">查看</div>
                    <div v-if="!disabled" class="remove" @click="removeUploaded(path)">移除</div>
                </div>
            </template>
        </div>
        <div class="wait-upload-list">
            <div v-if="state.currentFile" class="uploading-file">
                <div class="file"><span style="padding-right: 10px">{{ state.uploadStatus }}</span> {{ state.currentFile.name }}</div>
                <div :style="{width: state.uploadProgress}" class="progress"></div>
            </div>
            <template v-for="file in state.waitingUploadFileList" :key="file._id">
                <div class="uploaded-file">
                    <div class="file"><span style="padding-right: 10px">{{ file.status }}</span> {{ file.name }}</div>
                    <div v-if="!state.uploading" class="remove" @click="removeWaitUpload(file)">移除</div>
                </div>
            </template>
        </div>
        <template v-if="!disabled">
            <div v-show="max - state.uploadedPathList.length - state.waitingUploadFileList.length > 0" ref="dropPlaceholder" class="placeholder" @click="choose">
                将文件拖入或点击选择文件
            </div>
            <el-button v-if="state.waitingUploadFileList.length > 0 && !state.uploading" size="small" type="primary" @click="startUpload">开始上传</el-button>
        </template>
        <div v-if="disabled && state.uploadedPathList.length === 0" class="placeholder" style="color:#666;pointer-events: none">暂无文件</div>

    </div>
</template>

<script setup>
import {ref, watch, reactive, computed, onMounted} from "vue";
import {useStore} from "vuex";
import {useRouter} from "vue-router";
import * as uuid from "uuid";
import * as api from "./api.js"

const props = defineProps({
    modelValue: {
        type: String,
        default: () => ""
    },
    sourcePath: {
        type: String,
        default: () => ""
    },
    types: {
        type: String,
        default: () => ""
    },
    max: {
        type: Number,
        default: () => 1
    },
    params: {
        type: Object,
        default: () => {
        }
    },
    disabled: {
        type: Boolean,
        default: () => false
    }
});
const emits = defineEmits(["update:modelValue", "chooseFile"]);

// 路由
const router = useRouter();
// store
const store = useStore();

const state = reactive({
    // 已上传的文件地址列表
    uploadedPathList: [],
    // 已上传的文件源地址列表
    uploadedOriginalPathList: [],
    // 等待上传的文件列表
    waitingUploadFileList: [],
    // 正在上传文件
    currentFile: null,
    uploadStatus: "",
    uploadProgress: "",
    uploading: false
})

function getFileName(path) {
    if (path.indexOf("~~") > -1) return path.split("~~").at(-1)
    if (path.indexOf("/") > -1) return path.split("/").at(-1)
    return path
}

// 点击选择文件
function choose() {
    $chooseFile({
        count: props.max - state.uploadedPathList.length - state.waitingUploadFileList.length,
        extension: props.types ? props.types.toLowerCase().split("|") : null,
        success(files) {
            files = files.map(file => {
                file.status = "待上传";
                file.progress = "0%";
                return file
            })
            emits("chooseFile", files)
            state.waitingUploadFileList = state.waitingUploadFileList.concat(files)
        }
    })
}

// 删除已上传的
function removeUploaded(path) {
    const index = state.uploadedPathList.findIndex(item => item === path);
    if (index > -1) {
        state.uploadedPathList.splice(index, 1)
        try {
            state.uploadedOriginalPathList.splice(index, 1)
        } catch (e) {

        }
        updateValue()
    }
}

// 删除待上传
function removeWaitUpload(file) {
    const index = state.waitingUploadFileList.findIndex(item => item._id === file._id);
    if (index > -1) {
        state.waitingUploadFileList.splice(index, 1)
    }
}

// 开始上传
async function startUpload() {
    // 按顺序拿待上传列表中的第0 个进行上传
    const file = state.waitingUploadFileList[0];
    if (!file) return;
    state.currentFile = file;
    // 将第 0 个移除
    removeWaitUpload(file)
    const formData = new FormData();
    formData.append("fileList", state.currentFile);
    state.uploading = true;
    const {success, data} = await api.upload(props.params, formData, (e) => {
        const progressValue = parseFloat((e.progress * 100).toFixed(2)) + "%"
        state.uploadStatus = `上传中...${progressValue}`
        state.uploadProgress = progressValue;
        console.warning("上传进度", progressValue)
    });
    if (success && data) {
        // 上传成功
        state.uploadedPathList.push(data);
        state.currentFile = null;
        updateValue()
        state.uploading = false;
        // 继续上传
        setTimeout(() => {
            startUpload();
        }, 100)
    } else {
        // 上传失败
        state.currentFile.status = "待上传";
        state.currentFile.progress = "0%"
        state.waitingUploadFileList.unshift(state.currentFile);
        state.currentFile = null;
        state.uploading = false;
    }

}

function preview(path) {
    const width = 500;
    const height = 600;
    const left = (document.documentElement.clientWidth - width) / 2;
    window.open(window.$fileFullPath(path), "", `width=${width}, height=${height}, left=${height}, top=160`)
}

// 更新数据
function updateValue() {
    emits("update:modelValue", state.uploadedPathList.join(";"))
    emits("update:sourcePath", state.uploadedOriginalPathList.join(";"))
}

// 设置默认数据
function setDefault() {
    if (props.modelValue) {
        state.uploadedPathList = props.modelValue.split(";");
    }
}
function setSourcePath() {
    if (props.sourcePath) {
        state.uploadedOriginalPathList = props.sourcePath.split(";");
    }
}

watch(() => props.modelValue, () => {
    setDefault()
})
watch(() => props.sourcePath, () => {
    setSourcePath()
})
const dropPlaceholder = ref()

function initDrop() {
    if (!dropPlaceholder.value) return
    // 初始化数据
    dropPlaceholder.value.addEventListener("drop", e => {
        e.preventDefault(); //禁止浏览器默认行为，浏览器默认会直接打开显示
        if (e.type === 'drop') {
            //获取文件信息，同File对象相同
            const files = e.dataTransfer.files;
            const arr = [];
            for (let i = 0; i < files.length; i++) {
                const exten = files[i].name.split(".").at(-1).toLowerCase();
                files[i].exten = `.${exten}`;
                files[i]._id = uuid.v4();
                files[i].status = "待上传";
                files[i].progress = "0%";
                arr.push(files[i])
                if (props.types && props.types.toLowerCase().indexOf(`.${exten}`) < 0) {
                    return $message.warning(`文件类型不正确，请选择 ${props.types} 为后缀的文件`)
                }
            }
            emits("chooseFile", arr)
            state.waitingUploadFileList = state.waitingUploadFileList.concat(arr)

        }
    })
    dropPlaceholder.value.addEventListener('dragenter', e => {
        //禁止浏览器默认行为，浏览器默认会直接打开显示
        e.preventDefault();
    })
    dropPlaceholder.value.addEventListener('dragover', e => {
        //禁止浏览器默认行为，浏览器默认会直接打开显示
        e.preventDefault();
    })
}

onMounted(() => {
    initDrop();
    setDefault()
})
</script>

<style lang="scss" scoped>
.GFileListUpload {
    width: 100%;

    .uploaded-list {
        width: 100%;

        .uploaded-file {
            padding: 4px 0 4px 10px;
            box-sizing: border-box;
            border: 1px solid rgba(64, 158, 255, 1);
            font-size: 14px;
            display: flex;
            flex-direction: row;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 4px;
            background-color: rgba(236, 245, 255, 1);
            border-radius: 4px;

            .file {
                width: calc(100% - 100px);
                white-space: pre-wrap;
                word-wrap: break-word;
                line-height: 26px;
                color: rgba(64, 158, 255, 1);
            }

            .show {
                width: 50px;
                text-align: center;
                line-height: 26px;
                font-size: 14px;
                color: rgba(64, 158, 255, 1);
                cursor: pointer;

                &:active {
                    opacity: 0.7;
                }
            }

            .remove {
                width: 50px;
                text-align: center;
                line-height: 26px;
                font-size: 14px;
                color: rgba(245, 108, 108, 1);
                cursor: pointer;

                &:active {
                    opacity: 0.7;
                }
            }
        }

    }

    .wait-upload-list {
        width: 100%;

        .uploaded-file {
            padding: 4px 0 4px 10px;
            box-sizing: border-box;
            border: 1px dashed rgba(64, 158, 255, 1);
            font-size: 14px;
            display: flex;
            flex-direction: row;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 4px;
            border-radius: 4px;
            position: relative;;

            .file {
                width: calc(100% - 50px);
                white-space: pre-wrap;
                word-wrap: break-word;
                line-height: 26px;
                color: #666;
            }

            .remove {
                width: 50px;
                text-align: center;
                line-height: 26px;
                font-size: 14px;
                color: rgba(245, 108, 108, 1);
                cursor: pointer;

                &:active {
                    opacity: 0.7;
                }
            }

        }

        .uploading-file {
            border: 1px solid rgba(64, 158, 255, 1);
            padding: 4px 0 4px 10px;
            box-sizing: border-box;
            font-size: 14px;
            display: flex;
            flex-direction: row;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 4px;
            border-radius: 4px;
            position: relative;;

            .file {
                width: calc(100% - 50px);
                white-space: pre-wrap;
                word-wrap: break-word;
                line-height: 26px;
                color: #333;
            }

            .progress {
                position: absolute;
                left: 0;
                top: 0;
                bottom: 0;
                width: 0%;
                transition: width 0.3s ease;
                background-color: rgba(64, 158, 255, 1);
                z-index: -1;
            }
        }
    }

    .placeholder {
        padding: 6px 0 6px 10px;
        box-sizing: border-box;
        border: 1px dashed #dcdfe6;
        font-size: 14px;
        display: flex;
        flex-direction: row;
        justify-content: center;
        align-items: center;
        margin-bottom: 4px;
        background-color: rgba(0, 0, 0, .01);
        cursor: pointer;
        user-select: none;
        line-height: 26px;
        color: rgba(64, 158, 255, .8);
        border-radius: 4px;

        &:active {
            opacity: 0.7;
        }
    }
}
</style>